package com.example.utils;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.po.TableField;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.VelocityTemplateEngine;
import com.example.helper.NameHelper;
import org.springframework.util.StringUtils;

/**
 * 生成mybatis代码自动放入对应目录
 *
 * @author whw
 * @date 2019/12/30 16:57
 */
public class MyBatisGeneratorUtil {

    /**
     * 数据库类型
     */
    private DbType dbType = DbType.MYSQL;

    /**
     * 数据库连接信息
     */
    private String dbUrl = "jdbc:mysql://localhost:3306/db_demo?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=GMT%2b8";
    private String driver = "com.mysql.cj.jdbc.Driver";
    private String userName = "root";
    private String password = "123456";

    /**
     * 指定生成的表名。如果想生成整个库的，这里设为null即可
     */
    private String[] tableNames = new String[]{
            "t_user",
            "t_order"
    };

    /**
     * 输出路径（当前为项目根目录下）
     */
    private String outputDir = System.getProperty("user.dir") + "/generator-files";

    /**
     * 指定包名
     */
    private String packageName = "com.example";

    /**
     * service接口是否以I开头
     */
    private boolean serviceNameStartWithI = false;

    /**
     * controller基础类
     */
    private String superControllerClass = packageName + ".common.BaseController";

    /**
     * entity基础类
     */
    private String superEntityClass = packageName + ".common.BaseEntity";

    /**
     * 模块名 如果有模块名，则需在模块名前加. 例：.log
     */
    private String moduleName = "";

    /**
     * 作者名
     */
    private String author = "MyBatisGenerator";

    /**
     * 生成代码的调用方法
     */
    public void generateCode() {
        generateByTables(tableNames);
    }

    /**
     * 根据表自动生成
     *
     * @param tableNames 表名
     */
    private void generateByTables(String... tableNames) {
        //配置数据源
        DataSourceConfig dataSourceConfig = getDataSourceConfig();
        // 策略配置
        StrategyConfig strategyConfig = getStrategyConfig(tableNames);
        //全局变量配置
        GlobalConfig globalConfig = getGlobalConfig();
        //包名配置
        PackageConfig packageConfig = getPackageConfig();
        //自动生成
        atuoGenerator(dataSourceConfig, strategyConfig, globalConfig, packageConfig);
    }

    /**
     * 集成
     *
     * @param dataSourceConfig 配置数据源
     * @param strategyConfig   策略配置
     * @param config           全局变量配置
     * @param packageConfig    包名配置
     */
    private void atuoGenerator(DataSourceConfig dataSourceConfig, StrategyConfig strategyConfig, GlobalConfig config, PackageConfig packageConfig) {
        TemplateConfig tc = new TemplateConfig();
        tc.setController("/templates/controller.java.vm");
        tc.setService("/templates/service.java.vm");
        tc.setServiceImpl("/templates/serviceImpl.java.vm");
        tc.setEntity("/templates/entity.java.vm");
        tc.setMapper("/templates/mapper.java.vm");
        tc.setXml("/templates/mapper.xml.vm");

        new AutoGenerator()
                .setGlobalConfig(config)
                .setDataSource(dataSourceConfig)
                .setStrategy(strategyConfig)
                .setPackageInfo(packageConfig)
                // .setTemplateEngine(new FreemarkerTemplateEngine())
                .setTemplateEngine(new VelocityTemplateEngine()).setTemplate(tc)
                .execute();
    }

    /**
     * 设置包名
     *
     * @return PackageConfig 包名配置
     */
    private PackageConfig getPackageConfig() {
        PackageConfig config = new PackageConfig();
        config.setParent(packageName);
        if (!StringUtils.isEmpty(moduleName)) {
            config.setXml("mapper.xml" + moduleName);
            config.setMapper("mapper." + moduleName);
            config.setController("controller." + moduleName);
            config.setEntity("entity." + moduleName);
        }

        return config;
    }

    /**
     * 全局配置
     *
     * @return GlobalConfig
     */
    private GlobalConfig getGlobalConfig() {
        GlobalConfig globalConfig = new GlobalConfig();
        globalConfig
                // 开启swagger
                .setSwagger2(true)
                .setBaseColumnList(true)
                .setBaseResultMap(true)
                .setActiveRecord(true)
                //作者
                .setAuthor(author)
                //设置输出路径
                .setOutputDir(outputDir)
                .setFileOverride(true);
        if (!serviceNameStartWithI) {
            //设置service名
            globalConfig.setServiceName("%sService");
        }
        return globalConfig;
    }

    /**
     * 策略配置
     *
     * @param tableNames 表名
     * @return StrategyConfig
     */
    private StrategyConfig getStrategyConfig(String... tableNames) {
        return new StrategyConfig()
                // 全局大写命名 ORACLE 注意
                .setCapitalMode(true)
                //从数据库表到文件的命名策略
                .setNaming(NamingStrategy.underline_to_camel)
                .setNameConvert(new INameConvert() {
                    @Override
                    public String entityNameConvert(TableInfo tableInfo) {
                        return NameHelper.getName(tableInfo.getName(), true);
                    }

                    @Override
                    public String propertyNameConvert(TableField field) {
                        return NameHelper.getName(field.getName(), false);
                    }
                })
                //需要生成的的表名，多个表名传数组
                .setInclude(tableNames)

                //公共父类
                // .setSuperControllerClass(superControllerClass)
                // .setSuperEntityClass(superEntityClass)
                // 写于父类中的公共字段
                // .setSuperEntityColumns("id")
                //使用lombok
                .setEntityLombokModel(true)
                //rest风格
                .setRestControllerStyle(true);
    }

    /**
     * 配置数据源
     *
     * @return 数据源配置 DataSourceConfig
     */
    private DataSourceConfig getDataSourceConfig() {
        return new DataSourceConfig().setDbType(dbType)
                .setUrl(dbUrl)
                .setUsername(userName)
                .setPassword(password)
                .setDriverName(driver);
    }
}
